#ifndef _MY_MICRO_FUN_H_
#define _MY_MICRO_FUN_H_

#include "mytype.h"

#define str_member_offset(str_type, member) ((uu32)(&((str_type *)0)->member))

#define str16_member_pos(str_type, member) (str_member_offset(str_type, member) / 2)
#define str32_member_pos(str_type, member) (str_member_offset(str_type, member) / 4)
#define str64_member_pos(str_type, member) (str_member_offset(str_type, member) / 8)

#define is_align(a, x) (0 == ((UU32)(a)) & ((x)-1))

#if !defined(ext_max)
#define ext_max(a, b) (((a) > (b)) ? (a) : (b))
#define ext_min(a, b) (((a) < (b)) ? (a) : (b))
#define ext_max3(a, b, c) ext_max(ext_max(a, b), c)
#define ext_min3(a, b, c) ext_min(ext_min(a, b), c)
#define ext_max4(a, b, c, d) ext_max(ext_max(a, b), ext_max(c, d))
#define ext_min4(a, b, c, d) ext_min(ext_min(a, b), ext_min(c, d))
#endif

#if !defined(MAX)
#define MAX(x, y) (((x) > (y)) ? (x) : (y))
#define MIN(x, y) (((x) < (y)) ? (x) : (y))
#endif

#define ext_abs(x) (((x) < 0) ? (-(x)) : (x))

#define swap32(ap, bp)  \
	{                   \
		UU32 temp = ap; \
		ap = bp;        \
		bp = temp;      \
	}

#define swap16(ap, bp)  \
	{                   \
		UU16 temp = ap; \
		ap = bp;        \
		bp = temp;      \
	}

#define swap08(ap, bp) \
	{                  \
		UU8 temp = ap; \
		ap = bp;       \
		bp = temp;     \
	}

#define ror08(word, shift) \
	((((uu08)word) >> ((uwcpu)(shift)&0x07)) | (((uu08)word) << ((-(uwcpu)(shift)) & 0x07)))
#define rol08(word, shift) \
	((((uu08)word) << ((uwcpu)(shift)&0x07)) | (((uu08)word) >> ((-(uwcpu)(shift)) & 0x07)))
#define ror16(word, shift) \
	((((uu16)word) >> ((uwcpu)(shift)&0x0F)) | (((uu16)word) << ((-(uwcpu)(shift)) & 0x0F)))
#define rol16(word, shift) \
	((((uu16)word) << ((uwcpu)(shift)&0x0F)) | (((uu16)word) >> ((-(uwcpu)(shift)) & 0x0F)))
#define ror32(word, shift) \
	((((uu32)word) >> ((uwcpu)(shift)&0x1F)) | (((uu32)word) << ((-(uwcpu)(shift)) & 0x1F)))
#define rol32(word, shift) \
	((((uu32)word) << ((uwcpu)(shift)&0x1F)) | (((uu32)word) >> ((-(uwcpu)(shift)) & 0x1F)))
#define ror64(word, shift) \
	((((uu64)word) >> ((uwcpu)(shift)&0x3F)) | (((uu64)word) << ((-(uwcpu)(shift)) & 0x3F)))
#define rol64(word, shift) \
	((((uu64)word) << ((uwcpu)(shift)&0x3F)) | (((uu64)word) >> ((-(uwcpu)(shift)) & 0x3F)))

#ifndef SetBit
#define SetBit(var, pos) ((var) |= (1ul << (pos)))
#define ClrBit(var, pos) ((var) &= ~(1ul << (pos)))
#define TogBit(var, pos) ((var) ^= (1ul << (pos)))
#define GetBit(var, pos) (((var) >> (pos)) & 1ul)
#define SetBitVal(var, pos, val) ((val)&1U) ? (SetBit(var, pos)) : (ClrBit(var, pos))
#endif

#ifndef set_bit
#define set_bit(var, pos) ((var) |= (1ul << (pos)))
#define clr_bit(var, pos) ((var) &= ~(1ul << (pos)))
#define tog_bit(var, pos) ((var) ^= (1ul << (pos)))
#define get_bit(var, pos) (((var) >> (pos)) & 1ul)
#define set_bit_val(var, pos, val) ((val)&1U) ? (set_bit(var, pos)) : (clr_bit(var, pos))
#endif

#ifndef bit_set
#define bit_set(var, pos) ((var) |= (1ul << (pos)))
#define bit_clr(var, pos) ((var) &= ~(1ul << (pos)))
#define bit_tog(var, pos) ((var) ^= (1ul << (pos)))
#define bit_get(var, pos) (((var) >> (pos)) & 1ul)
#define bit_set_val(var, pos, val) ((val)&1U) ? (bit_set(var, pos)) : (bit_clr(var, pos))
#endif

#define set_nbit(var, pos) ((var) &= ~(1ul << (pos)))
#define clr_nbit(var, pos) ((var) |= (1ul << (pos)))
#define nbit_set set_nbit
#define nbit_clr clr_nbit

#ifndef BIT_Msk
#define BIT_Msk(x) (1UL << (x))
#endif

#ifndef BIT
#define BIT BIT_Msk
#endif

#ifndef NBIT
#define NBIT(x) (~BIT_Msk(x))
#endif

#ifndef BITS_Msk
#define BITS_Msk(m, n) (((m) > (n)) ? ((UINT32_MAX >> (31 - (m))) & (UINT32_MAX << (n))) : ((UINT32_MAX >> (31 - (n))) & (UINT32_MAX << (m))))
#endif

#ifndef BITS
#define BITS BITS_Msk
#endif

#ifndef NBITS
#define NBITS(m, n) (~BITS_Msk(m, n))
#endif

#ifndef set_bits
#define set_bits(val, m, n) (val |= BITS_Msk(m, n))
#define clr_bits(val, m, n) (val &= ~BITS_Msk(m, n))
#define tog_bits(val, m, n) (val ^= BITS_Msk(m, n))
#define get_bits(val, m, n) (((m) > (n)) ? (((val)&BITS_Msk(m, n)) >> (n)) : (((val)&BITS_Msk(m, n)) >> (m)))
#define set_bits_val(var, m, n, val) var = (var & (~BITS_Msk(m, n))) | (get_bits(val, 0, (((m) > (n)) ? ((m) - (n)) : ((n) - (m)))) << (((m) > (n)) ? (n) : (m)))
#endif

#ifndef bits_set
#define bits_set set_bits
#define bits_clr clr_bits
#define bits_tog tog_bits
#define bits_get get_bits
#define bits_set_val set_bits_val
#endif

#ifndef set_mask
#define set_mask(var, mask) var = (var) | (mask)
#define clr_mask(var, mask) var = (var) & (~(mask))
#define get_mask(var, mask) ((var) & (mask))
#define cset_mask(var, clr, set) var = (((var) & (~(clr))) | (set))
#endif

#ifndef mask_set
#define mask_set set_mask
#define mask_clr clr_mask
#define mask_get get_mask
#define mask_cset cset_mask
#endif

#define map_bit_set(pmap, pos) bit_set(((uu8 *)(pmap))[(pos) >> 3], (pos)&7U)
#define map_bit_clr(pmap, pos) bit_clr(((uu8 *)(pmap))[(pos) >> 3], (pos)&7U)
#define map_bit_tog(pmap, pos) bit_tog(((uu8 *)(pmap))[(pos) >> 3], (pos)&7U)
#define map_bit_get(pmap, pos) bit_get(((uu8 *)(pmap))[(pos) >> 3], (pos)&7U)
#define map_bit_set_val(pmap, pos, val) bit_set_val(((uu8 *)(pmap))[(pos) >> 3], (pos)&7U, val)

#define map_bits_set(pmap, m, n) bits_set(((uu32 *)(pmap))[(m) >> 5], (m)&0x1FU, (n)&0x1FU)
#define map_bits_clr(pmap, m, n) bits_clr(((uu32 *)(pmap))[(m) >> 5], (m)&0x1FU, (n)&0x1FU)
#define map_bits_tog(pmap, m, n) bits_tog(((uu32 *)(pmap))[(m) >> 5], (m)&0x1FU, (n)&0x1FU)
#define map_bits_get(pmap, m, n) bits_get(((uu32 *)(pmap))[(m) >> 5], (m)&0x1FU, (n)&0x1FU)
#define map_bits_set_val(pmap, m, n, val) bits_set_val(((uu32 *)(pmap))[(m) >> 5], (m)&0x1FU, (n)&0x1FU, val)

#define group_bits1_set(var, gp, val) cset_mask(var, (0x01UL << (gp)*1), ((val) << (gp)*1))
#define group_bits2_set(var, gp, val) cset_mask(var, (0x03UL << (gp)*2), ((val) << (gp)*2))
#define group_bits3_set(var, gp, val) cset_mask(var, (0x07UL << (gp)*3), ((val) << (gp)*3))
#define group_bits4_set(var, gp, val) cset_mask(var, (0x0FUL << (gp)*4), ((val) << (gp)*4))
#define group_bits1_clr(var, gp) clr_mask(var, (0x01UL << (gp)*1))
#define group_bits2_clr(var, gp) clr_mask(var, (0x03UL << (gp)*2))
#define group_bits3_clr(var, gp) clr_mask(var, (0x07UL << (gp)*3))
#define group_bits4_clr(var, gp) clr_mask(var, (0x0FUL << (gp)*4))

#define multi32_bits1_set(var, gp, val) cset_mask(vu32p(&var)[(gp) >> 5], ((uu32)0x01U << ((gp)&0x1F) * 1), ((val) << ((gp)&0x1F) * 1))
#define multi32_bits2_set(var, gp, val) cset_mask(vu32p(&var)[(gp) >> 4], ((uu32)0x03U << ((gp)&0x0F) * 2), ((val) << ((gp)&0x0F) * 2))
#define multi32_bits3_set(var, gp, val) cset_mask(vu32p(&var)[(gp) / 10], ((uu32)0x07U << ((gp) % 10) * 3), ((val) << ((gp) % 10) * 3))
#define multi32_bits4_set(var, gp, val) cset_mask(vu32p(&var)[(gp) >> 3], ((uu32)0x0FU << ((gp)&0x07) * 4), ((val) << ((gp)&0x07) * 4))
#define multi32_bits5_set(var, gp, val) cset_mask(vu32p(&var)[(gp) / 6], ((uu32)0x1FU << ((gp) % 6) * 5), ((val) << ((gp) % 6) * 5))

#define multi16_bits1_set(var, gp, val) cset_mask(vu16p(&var)[(gp) >> 4], ((uu16)0x01U << ((gp)&0x0F) * 1), ((val) << ((gp)&0x0F) * 1))
#define multi16_bits2_set(var, gp, val) cset_mask(vu16p(&var)[(gp) >> 3], ((uu16)0x03U << ((gp)&0x07) * 2), ((val) << ((gp)&0x07) * 2))
#define multi16_bits4_set(var, gp, val) cset_mask(vu16p(&var)[(gp) >> 2], ((uu16)0x0FU << ((gp)&0x03) * 4), ((val) << ((gp)&0x03) * 4))

#define multi8_bits1_set(var, gp, val) cset_mask(vu8p(&var)[(gp) >> 3], ((uu8)0x01U << ((gp)&0x07) * 1), ((val) << ((gp)&0x07) * 1))
#define multi8_bits2_set(var, gp, val) cset_mask(vu8p(&var)[(gp) >> 2], ((uu8)0x03U << ((gp)&0x03) * 2), ((val) << ((gp)&0x03) * 2))
#define multi8_bits4_set(var, gp, val) cset_mask(vu8p(&var)[(gp) >> 1], ((uu8)0x0FU << ((gp)&0x01) * 4), ((val) << ((gp)&0x01) * 4))

#define u8_lbit_seg_set(var, vpos, dat, dpos, blen)                                 \
	{                                                                               \
		uu8 mask = (U8_MAX << vpos) & (U8_MAX >> (8 - (vpos + blen)));              \
		var = (vpos >= dpos) ? ((var & (~mask)) | ((dat << (vpos - dpos)) & mask))  \
							 : ((var & (~mask)) | ((dat >> (dpos - vpos)) & mask)); \
	}

#define u16_lbit_seg_set(var, vpos, dat, dpos, blen)                                \
	{                                                                               \
		uu16 mask = (U16_MAX << vpos) & (U16_MAX >> (16 - (vpos + blen)));          \
		var = (vpos >= dpos) ? ((var & (~mask)) | ((dat << (vpos - dpos)) & mask))  \
							 : ((var & (~mask)) | ((dat >> (dpos - vpos)) & mask)); \
	}

#define u32_lbit_seg_set(var, vpos, dat, dpos, blen)                                \
	{                                                                               \
		uu32 mask = (U32_MAX << vpos) & (U32_MAX >> (32 - (vpos + blen)));          \
		var = (vpos >= dpos) ? ((var & (~mask)) | ((dat << (vpos - dpos)) & mask))  \
							 : ((var & (~mask)) | ((dat >> (dpos - vpos)) & mask)); \
	}

#define u8_bbit_seg_set(var, vpos, dat, dpos, blen)                                 \
	{                                                                               \
		uu8 mask = (U8_MAX >> vpos) & (U8_MAX << (8 - (vpos + blen)));              \
		var = (vpos >= dpos) ? ((var & (~mask)) | ((dat >> (vpos - dpos)) & mask))  \
							 : ((var & (~mask)) | ((dat << (dpos - vpos)) & mask)); \
	}

#define u16_bbit_seg_set(var, vpos, dat, dpos, blen)                                \
	{                                                                               \
		uu16 mask = (U16_MAX >> vpos) & (U16_MAX << (16 - (vpos + blen)));          \
		var = (vpos >= dpos) ? ((var & (~mask)) | ((dat >> (vpos - dpos)) & mask))  \
							 : ((var & (~mask)) | ((dat << (dpos - vpos)) & mask)); \
	}

#define u32_bbit_seg_set(var, vpos, dat, dpos, blen)                                \
	{                                                                               \
		uu32 mask = (U32_MAX >> vpos) & (U32_MAX << (32 - (vpos + blen)));          \
		var = (vpos >= dpos) ? ((var & (~mask)) | ((dat >> (vpos - dpos)) & mask))  \
							 : ((var & (~mask)) | ((dat << (dpos - vpos)) & mask)); \
	}

#define rang_offset(val, set, offset) ((((val) + (offset)) >= (set)) && ((val) <= ((set) + (offset))))
#define rang_check(val, min, max) (((val) >= (min)) && ((val) <= (max)))
#define rang_limit(val, min, max) \
	if (val < (min))              \
		val = min;                \
	else if (val > (max))         \
	val = max

#define rang_limit_low(val, min) \
	if (val < (min))             \
	val = min

#define rang_limit_high(val, max) \
	if (val > (max))              \
	val = max

#define array_len(x) (sizeof(x) / sizeof(x[0]))
#define arr_len array_len
#define arr_size array_len
#define arrray_size array_len

#define asc_dec_check(ch) (((ch) >= '0') && ((ch) <= '9'))
#define asc_oct_check(ch) (((ch) >= '0') && ((ch) <= '7'))
#define asc_hex_check(ch) (asc_dec_check(ch) || (((ch) >= 'A') && ((ch) <= 'F')) || (((ch) >= 'a') && ((ch) <= 'f')))

#define loop(x) for (int index = 0; index < (x); index++)
#define each(array) for (int index = 0; index < sizeof(array) / sizeof(array[0]); index++)
#define loop_n(x) for (int index = 0; index < (x); index++)

#define var_loop_inc(var, min, max) \
	var++;                          \
	if (var > (max))                \
		var = (min);

#define var_loop_dec(var, min, max) \
	var--;                          \
	if (var < (min))                \
		var = (max);

#define var_limit_inc(var, max) \
	var++;                      \
	if (var > (max))            \
		var = (max);

#define var_limit_dec(var, min) \
	var--;                      \
	if (var < (min))            \
		var = (min);

#ifndef outpw
#define outpw(port, value) *((volatile unsigned long *)(port)) = value
#define inpw(port) (*((volatile unsigned long *)(port)))
#define outps(port, value) *((volatile unsigned short *)(port)) = value
#define inps(port) (*((volatile unsigned short *)(port)))
#define outpb(port, value) *((volatile unsigned char *)(port)) = value
#define inpb(port) (*((volatile unsigned char *)(port)))
#define outp32(port, value) *((volatile unsigned long *)(port)) = value
#define inp32(port) (*((volatile unsigned long *)(port)))
#define outp16(port, value) *((volatile unsigned short *)(port)) = value
#define inp16(port) (*((volatile unsigned short *)(port)))
#define outp8(port, value) *((volatile unsigned char *)(port)) = value
#define inp8(port) (*((volatile unsigned char *)(port)))
#endif

#define inpf32(port) (*((volatile float *)(port)))
#define outpf32(port, value) *((volatile float *)(port)) = value
#define inpf64(port) (*((volatile double *)(port)))
#define outfd64(port, value) *((volatile double *)(port)) = value
#define inp64(port) (*((volatile unsigned long long *)(port)))
#define outp64(port, value) *((volatile unsigned long long *)(port)) = value

#define ext_mem64(port) (*((volatile unsigned long long *)(port)))
#define ext_mem32(port) (*((volatile unsigned long *)(port)))
#define ext_mem16(port) (*((volatile unsigned short *)(port)))
#define ext_mem8(port) (*((volatile unsigned char *)(port)))

#ifndef mem32
#define mem64 ext_mem64
#define mem32 ext_mem32
#define mem16 ext_mem16
#define mem8 ext_mem8
#endif

#define byte_lb(x) (x & 0xFF)
#define byte_hb(x) ((x >> 8) & 0xFF)
#define byte_ub(x) ((x >> 16) & 0xFF)
#define byte_mb(x) ((x >> 24) & 0xFF)

#define word_lw(x) (x & 0xFFFF)
#define word_hw(x) ((x >> 16) & 0xFFFF)

#define word_make(hb, lb) ((UU16)((UU8)(lb) | ((UU8)(hb) << 8)))
#define dword_make(hw, lw) ((UU32)((UU16)(lw) | ((UU16)(hw) << 16)))
#define dword_wmake(hw, lw) ((UU32)((UU16)(lw) | ((UU16)(hw) << 16)))
#define dword_bmake(mb, ub, hb, lb) ((UU32)(((UU8)(mb) << 24) | ((UU8)(ub) << 16) | ((UU8)(hb) << 8) | ((UU8)(lb) << 0)))

#endif 
